#include "FigureFactory.h"

FigureFactory* FigureFactory::instance = 0;

using namespace std;

FigureFactory::FigureFactory(){
}

void FigureFactory::destroy(){
	if(FigureFactory::instance!=NULL)
		delete FigureFactory::instance;
	FigureFactory::instance = NULL;
} 

FigureFactory::~FigureFactory(){}


FigureFactory* FigureFactory::getInstance(){
	if(!FigureFactory::instance)
		FigureFactory::instance = new FigureFactory();
	return FigureFactory::instance;
}

Figure* FigureFactory::createSegment(MapList* parameters) throw (InvalidFigureException){
	int x0=0;
	int y0=0;
	int x1=0;
	int y1=0;
	int width=0;
	int height=0;
	std::string id;
	std::string lineColorStr;
	Color *lineColor;
	bool isLineColor = false;
	
	/* Obtengo los Attributos obligatorios para poder crear un Segmento
	 * si alguno de estos atributos no esta no lo puedo dibujar*/
	try{
		CustomizedMap *mapSegment = parameters->getElement(parameters->getType());

		id = mapSegment->getAttribute("id");
		if (id.compare("")==0)
			throw InvalidFigureException("Id invalido no se puede crear el segmento");
	
		CustomizedMap *mapInicio = parameters->getElement("inicio");

		ValidatorUtils::converToInt(mapInicio->getAttribute("x").c_str(),&x0);
		ValidatorUtils::converToInt(mapInicio->getAttribute("y").c_str(),&y0);

		CustomizedMap *mapFin = parameters->getElement("fin");

		ValidatorUtils::converToInt(mapFin->getAttribute("x").c_str(),&x1);
		ValidatorUtils::converToInt(mapFin->getAttribute("y").c_str(),&y1);

		try{
			lineColorStr = mapSegment->getAttribute("colorLinea");
			isLineColor = true;
			
		}catch(AttributeNotFoundException &e){
			Logger::get_instance()->log("La Figura de id "+id+" no tiene un color asociado");
		}

		if(isLineColor){
			try{
				lineColor = ColorFactory::getInstance()->getColor(lineColorStr);
			}catch(InvalidColorException &e){
				Logger::get_instance()->log(e);
				Logger::get_instance()->log("Utilizando color default para la Figura id :"+id);
				lineColor = new Color(*DefaultParameterContainer::getInstance()->getLineColor());
			}
		}else {
			Logger::get_instance()->get_instance()->log("Se graficara con color default la Figura id: "+id);
			lineColor = new Color(*DefaultParameterContainer::getInstance()->getLineColor());
		}

		delete mapSegment;
		delete mapInicio;
		delete mapFin;

		return new Segment(id,Point(x0,y0),Point(x1,y1), lineColor);

	}catch(AttributeNotFoundException &e){
		throw InvalidFigureException("El Segmento no ha podido ser creado, falta un atributo");
	}catch(ElementNotFoundException &e){
		throw InvalidFigureException("El Segmento no ha podido ser creado, falta un elemento");
	}catch(InvalidIntegerException &e){
		Logger::get_instance()->log(e);
		throw InvalidFigureException("El segmento de id :'"+ id +"' no pudo ser creada, error de tipos");
	}
}


Figure* FigureFactory::createRectangle(MapList* parameters) throw (InvalidFigureException){
	int x=0;
	int y=0;
	int width=0;
	int height=0;
	std::string id;
	std::string textureId;
	std::string figureColorStr;
	std::string lineColorStr;
	bool isTextured = false;
	bool isLineColor = false;
	bool foundTexure = false;
	bool isFigureColor = false;
	Color* lineColor = NULL;
	Color* figureColor = NULL;

	try{

		CustomizedMap *mapRectangle = parameters->getElement(parameters->getType());

		id = mapRectangle->getAttribute("id");
		if (id.compare("")==0)
			throw InvalidFigureException("Id invalido no se puede crear el rectangulo");

		ValidatorUtils::converToInt(mapRectangle->getAttribute("base").c_str(),&width);
		if (width == 0)
			throw InvalidFigureException("La base debe ser mayor a cero, no se puede crear el circulo");
		
		ValidatorUtils::converToInt(mapRectangle->getAttribute("altura").c_str(),&height);
		if (height == 0)
			throw InvalidFigureException("La altura debe ser mayor a cero, no se puede crear el circulo");
		

		CustomizedMap *mapPos = parameters->getElement("posicion");

		ValidatorUtils::converToInt(mapPos->getAttribute("x").c_str(),&x);
		ValidatorUtils::converToInt(mapPos->getAttribute("y").c_str(),&y);

		//Verifico si tiene textura no hago nada si no encuentro el attributo
		
		try{
			textureId = mapRectangle->getAttribute("textura");
			isTextured = true;
		}catch(AttributeNotFoundException &e){}

		//Verifico si tiene color de Relleno no hago nada si no lo encuentro
		try{
			figureColorStr = mapRectangle->getAttribute("colorFigura");
			isFigureColor= true;
		}catch(AttributeNotFoundException &e){
			figureColor = new Color(*DefaultParameterContainer::getInstance()->getFigureColor());
			isFigureColor=true;
		}

		try{
			lineColorStr = mapRectangle->getAttribute("colorLinea");
			isLineColor = true; 
		}catch(AttributeNotFoundException &e){}

		
		if(isLineColor){
			try{
				lineColor = ColorFactory::getInstance()->getColor(lineColorStr);
			}catch(InvalidColorException &e){
				Logger::get_instance()->log(e);
				Logger::get_instance()->log("Utilizando color default para la fig id:"+id);
				lineColor = new Color(*DefaultParameterContainer::getInstance()->getLineColor());
			}
		} else if((!isFigureColor)&&(!isTextured)){
			Logger::get_instance()->get_instance()->log("Se graficara con color default la Figura id: "+id);
			lineColor = new Color(*DefaultParameterContainer::getInstance()->getLineColor());
		}

		if(isFigureColor){
			try{
				if(figureColor==NULL)
					figureColor = ColorFactory::getInstance()->getColor(figureColorStr);
			}catch(InvalidColorException &e){
				Logger::get_instance()->log(e);
				isFigureColor = false;
			}
		}
		

		delete mapRectangle;
		delete mapPos;

		// ((isTextured) && (isFigureColor))
		//hrow InvalidFigureException("No se puede graficar el rectangulo id: '"+id+"', tiene relleno y textura");

		if(isTextured&&(!isLineColor)){
			try{
				Texture * texture  = TextureContainer::getInstance()->getTextureById(textureId);
				return new Rectangle(id,Point(x,y), width, height, texture);
			}catch(TextureNotFoundException &e){
				throw InvalidFigureException("No se encontro la textura id: "+textureId+" en la figura de id: ' "+id+" '");
			}
		}

		if(isTextured&&isLineColor){
			try{
				Texture * texture  = TextureContainer::getInstance()->getTextureById(textureId);
				return new Rectangle(id,Point(x,y),width, height,lineColor,texture);
			}catch(TextureNotFoundException &e){
				throw InvalidFigureException("No se encontro la textura id: "+textureId+" en la figura de id: ' "+id+" '");
			}
		}

		if(isFigureColor)
			return new Rectangle(id,Point(x,y),width, height,lineColor,figureColor);
		else 
			return new Rectangle(id,Point(x,y),width, height,lineColor);
		
	}catch(AttributeNotFoundException &e){
		throw InvalidFigureException("La figura no pudo ser creada, porque falta algun atributo");
	}catch(ElementNotFoundException &e){
		throw InvalidFigureException("La figura no pudo ser creada, porque no se encontro un elemento");
	}catch(InvalidIntegerException &e){
		Logger::get_instance()->log(e);
		throw InvalidFigureException("El Rectagulo de id: '"+id+"' no pudo ser creada, error de tipos");
	}
	
}


Figure* FigureFactory::createCircle(MapList* parameters) throw (InvalidFigureException){
	std::string id;
	int x=0;
	int y=0;
	int radio=0;
	bool isTextured = false;
	bool isFigureColor = false;
	bool isLineColor = false;
	std::string lineColorStr;
	std::string figureColorStr;
	std::string textureId;
	Color *lineColor = NULL;
	Color *figureColor = NULL;

	try{
		CustomizedMap *mapCircle = parameters->getElement(parameters->getType());

		id = mapCircle->getAttribute("id");
		if (id.compare("")==0) 
			throw InvalidFigureException("Id invalido no se puede crear el circulo");

		ValidatorUtils::converToInt(mapCircle->getAttribute("radio").c_str(),&radio);
		if (radio == 0)
			throw InvalidFigureException("El radio debe ser mayor a cero, no se puede crear el circulo");
				
		CustomizedMap *mapPos = parameters->getElement("posicion");
		ValidatorUtils::converToInt(mapPos->getAttribute("x").c_str(),&x);
		ValidatorUtils::converToInt(mapPos->getAttribute("y").c_str(),&y);

		//Me fijo si hay una textura en la lista de attributos del circulo
		try{
			textureId = mapCircle->getAttribute("textura");	
			isTextured = true; 
		}catch(AttributeNotFoundException &e){}

	
		try{
			figureColorStr = mapCircle->getAttribute("colorFigura");
			isFigureColor = true;
		}catch(AttributeNotFoundException &e){
			figureColor = new Color(*DefaultParameterContainer::getInstance()->getFigureColor());
			isFigureColor=true;
		}

	
		try{
			lineColorStr = mapCircle->getAttribute("colorLinea");
			isLineColor = true;
		}catch(AttributeNotFoundException &e){}

		if(isLineColor){
			try{
				lineColor = ColorFactory::getInstance()->getColor(lineColorStr);
			}catch(InvalidColorException &e){
				Logger::get_instance()->log(e);
				Logger::get_instance()->log("Utilizando color default para la fig id:"+id);
				lineColor = new Color(*DefaultParameterContainer::getInstance()->getLineColor());
			}
		} else if((!isFigureColor)&&(!isTextured)){
			Logger::get_instance()->get_instance()->log("Se graficara con color default la Figura id: "+id);
			lineColor = new Color(*DefaultParameterContainer::getInstance()->getLineColor());
		}

		if(isFigureColor){
			try{
				if(figureColor==NULL)
					figureColor = ColorFactory::getInstance()->getColor(figureColorStr);
			}catch(InvalidColorException &e){
				Logger::get_instance()->log(e);
				isFigureColor = false;
			}
		}
		

		delete mapCircle;
		delete mapPos;

		// ((isTextured) && (isFigureColor))
		//hrow InvalidFigureException("No se puede graficar el circulo de id '"+id+"', tiene relleno y textura");

		if(isTextured&&(!isLineColor)){
			try{
				Texture * texture  = TextureContainer::getInstance()->getTextureById(textureId);
				return new Circle(id,Point(x,y),radio,texture);
			}catch(TextureNotFoundException &e){
				throw InvalidFigureException("No se encontro la textura id: "+textureId+" en la figura de id: ' "+id+" '");
			}
		}

		if(isTextured&&isLineColor){
			try{
				Texture * texture  = TextureContainer::getInstance()->getTextureById(textureId);
				return new Circle(id,Point(x,y),radio,lineColor,texture);
			}catch(TextureNotFoundException &e){
				throw InvalidFigureException("No se encontro la textura id: "+textureId+" en la figura de id: ' "+id+" '");
			}
		}

		if(isFigureColor)
			return new Circle(id,Point(x,y),radio,lineColor,figureColor);
		else 
			return new Circle(id,Point(x,y),radio,lineColor);
		
	}catch(AttributeNotFoundException &e){
		throw InvalidFigureException("El circulo no ha podido ser creado");
	}catch(ElementNotFoundException &e){
		throw InvalidFigureException("El circulo no ha podido ser creado");
	}catch(InvalidIntegerException &e){
		Logger::get_instance()->log(e);
		throw InvalidFigureException("El circulo de id:'"+id+"' no pudo ser creada, error de tipos");
	}
	
}

Figure * FigureFactory::createSquare(MapList* parameters) throw (InvalidFigureException){
	int x=0;
	int y=0;
	int side=0;
	std::string textureId;
	std::string figureColorStr;
	std::string lineColorStr;
	bool isTextured = false;
	bool isLineColor = false;
	bool foundTexure = false;
	bool isFigureColor = false;
	Color *figureColor = NULL;
	Color *lineColor = NULL;
	std::string id;
	/* Estos son los parametros obligatorios para crear los cuadrados */
	try{
		CustomizedMap *mapSquare = parameters->getElement(parameters->getType());

		id = mapSquare->getAttribute("id");
		if (id.compare("")==0)
			throw InvalidFigureException("Id invalido no se puede crear el cuadrado");
		
		ValidatorUtils::converToInt(mapSquare->getAttribute("lado").c_str(),&side);
		if (side == 0)
			throw InvalidFigureException("El lado debe ser mayor a cero, no se puede crear el cuadrado");
		
		CustomizedMap *mapPos = parameters->getElement("posicion");

		ValidatorUtils::converToInt(mapPos->getAttribute("x").c_str(),&x);
		ValidatorUtils::converToInt(mapPos->getAttribute("y").c_str(),&y);

		//Verifico si tiene textura no hago nada si no encuentro el attributo
		
		try{
			textureId = mapSquare->getAttribute("textura");
			isTextured = true;
		}catch(AttributeNotFoundException &e){}

		//Verifico si tiene color de Relleno no hago nada si no lo encuentro
		try{
			figureColorStr = mapSquare->getAttribute("colorFigura");
			isFigureColor= true;
		}catch(AttributeNotFoundException &e){
			figureColor = new Color(*DefaultParameterContainer::getInstance()->getFigureColor());
			isFigureColor=true;
		}

		try{
			lineColorStr = mapSquare->getAttribute("colorLinea");
			isLineColor = true;
		}catch(AttributeNotFoundException &e){
		}

		if(isLineColor){
			try{
				lineColor = ColorFactory::getInstance()->getColor(lineColorStr);
			}catch(InvalidColorException &e){
				Logger::get_instance()->log(e);
				Logger::get_instance()->log("Utilizando color default para la fig id:"+id);
				lineColor = new Color(*DefaultParameterContainer::getInstance()->getLineColor());
			}
		} else if((!isFigureColor)&&(!isTextured)){
			Logger::get_instance()->get_instance()->log("Se graficara con color default la Figura id: "+id);
			lineColor = new Color(*DefaultParameterContainer::getInstance()->getLineColor());
		}

		if(isFigureColor){
			try{
				if(figureColor==NULL)
					figureColor = ColorFactory::getInstance()->getColor(figureColorStr);
			}catch(InvalidColorException &e){
				Logger::get_instance()->log(e);
				isFigureColor = false;
			}
		}

		delete mapSquare;
		delete mapPos;

		// ((isTextured) && (isFigureColor))
		//hrow InvalidFigureException("No se puede graficar el rectangulo id: '"+id+"', tiene relleno y textura");

		if(isTextured&&(!isLineColor)){
			try{
				Texture * texture  = TextureContainer::getInstance()->getTextureById(textureId);
				return new Square(id,Point(x,y), side, texture);
			}catch(TextureNotFoundException &e){
				throw InvalidFigureException("No se encontro la textura id: "+textureId+" en la figura de id: ' "+id+" '");
			}
		}

		if(isTextured&&isLineColor){
			try{
				Texture * texture  = TextureContainer::getInstance()->getTextureById(textureId);
				return new Square(id,Point(x,y),side,lineColor,texture);
			}catch(TextureNotFoundException &e){
				throw InvalidFigureException("No se encontro la textura id: "+textureId+" en la figura de id: ' "+id+" '");
			}
		}

		if(isFigureColor)
			return new Square(id,Point(x,y), side ,lineColor,figureColor);
		else 
			return new Square(id, Point(x,y) , side ,lineColor);
	}catch(AttributeNotFoundException &e){
		throw InvalidFigureException("La figura no pudo ser creada, porque falta algun atributo");
	}catch(ElementNotFoundException &e){
		throw InvalidFigureException("La figura no pudo ser creada, porque no se encontro un elemento");
	}catch(InvalidIntegerException &e){
		Logger::get_instance()->log(e);
		throw InvalidFigureException("'" + id + "' no pudo ser creado, error de tipos");
	}
}


Figure* FigureFactory::getFigure(ObjectType &type, MapList* parameters) throw (InvalidObjectTypeException){
	switch (type){
		case square: return createSquare(parameters);
		case rectangle: return createRectangle(parameters);
		case circle : return createCircle(parameters);
		case segment : return createSegment(parameters);
		default : throw InvalidObjectTypeException("Esto no deberia pasar ya verifique el tipo arriba");
	}
}